//测试CookTorrance的高光反射

#version 450
#extension GL_ARB_separate_shader_objects : enable

#include "/Utils.glsl"

//输入-从顶点着色器
layout(location = 0) in vec3 vs_fs_normal;
layout(location = 1) in vec3 vs_fs_tangent;
layout(location = 2) in vec2 vs_fs_TexCoord;
layout(location = 3) in vec3 vs_fs_worldPosition;

//输出
layout(location = 0) out vec4 fColor;

//纹理
layout(binding = 1) uniform sampler2D albedoTexture;
layout(binding = 2) uniform sampler2D metallicTexture;
layout(binding = 3) uniform sampler2D roughnessTexture;
layout(binding = 4) uniform sampler2D normalTexture;
layout(binding = 9) uniform samplerCube skyboxCubeMap;
layout(binding = 8) uniform samplerCube skyboxDiffuseCubeMap;

//UniformBuffer
layout(binding = 7) uniform SceneData {
	mat4 view;
	mat4 proj;
	vec4 lightDir;
	vec4 eyePosition;
	vec4 TestValue;
} ub_SceneData;


//GGX采样微面元法线
//sampleNum：采样数目，用于产生随机值
//sampleCount：采样总数
//a：GGX中的粗糙度
//N：宏观表面的法线
vec3 GGXsampleMicroNormal(int sampleNum, int sampleCount, float a, vec3 N)
{
	//使用Hammersley生成随机值：
	vec2 rand = Hammersley(sampleNum, sampleCount);
	//公式中输入的两个随机值：
	float xi_1 = rand.x;
	float xi_2 = rand.y;

	//使用公式生成极角：
	float theta = atan(a * sqrt(xi_1) / sqrt(1 - xi_1));
	//使用公式生成方位角：
	float phi = 2 * PI * xi_2;

	//生成一个任意的以法线为Z轴的坐标系（XY轴的朝向是无所谓的，因为phi在2PI内均匀随机）
	vec3 NotN = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);//任意一个不是N的方向
	vec3 T = normalize(cross(NotN, N));	//叉乘得到切线，一定和法线垂直
	vec3 B = cross(N, T);		//叉乘得到副法线，一定和法线以及切线垂直

	//将方向变换到世界空间：
	return T * (sin(theta) * cos(phi)) +
		B * (sin(theta) * sin(phi)) +
		N * cos(theta);
}

//GGX的几何函数
//a：粗糙度
//w：要检查的方向（入射或出射）
//m：微面元的法线
//n：宏观表面的法线
float GGX_Geometry(float a, vec3 w, vec3 m, vec3 n)
{
	float w_d_m = dot(w, m);
	float w_d_n = dot(w, n);
	float tanTheta2 = (1.0 - pow(w_d_n, 2)) / pow(w_d_n, 2);
	return chi(w_d_m / w_d_n) * 2 /
		(1 + sqrt(1 + a * a * tanTheta2));
}

//Schlick的Fresnel：
vec3 Fresnel_Schlick(vec3 F0, vec3 normal, vec3 view)
{
	float cosTheta = dot(normalize(view), normalize(normal));
	return F0 + (vec3(1, 1, 1) - F0) * pow(1 - cosTheta, 5);
}

//计算CookTorrance的高光
//normal：宏观表面的法线朝向
//view：视线方向
//roughness：表面粗糙度
//FO：0°的菲涅尔值
//kS：高光部分占总体光的百分比，此值在此函数中计算得到
vec3 CookTorranceSpecular(vec3 normal, vec3 view, float roughness, vec3 F0, out vec3 kS)
{
	vec3 radiance;//最终的高光结果。会进行累加然后平均化

	int sampleCount = 100;	//采样次数
	for (int i = 0; i < sampleCount; i++)
	{
		//当前采样中的微面元的法线方向：
		vec3 MicroNormal = GGXsampleMicroNormal(i, sampleCount, roughness, normal);
		//反射光方向（或者说来自此方向上的光将会反射到视线方向上）
		vec3 lightDir = -reflect(view, MicroNormal);

		//计算一些点乘的值方便后续运算：
		float NoV = clamp(dot(normal, view), 0.0, 1.0);
		float NoL = clamp(dot(normal, lightDir), 0.0, 1.0);
		float NoH = clamp(dot(normal, MicroNormal), 0.0, 1.0);
		float VoH = clamp(dot(view, MicroNormal), 0.0, 1.0);
		if (NoL > 0)
		{
			//计算菲涅尔
			vec3 F = Fresnel_Schlick(F0, normal, view);
			//累加统计高光系数
			kS += F;

			//计算几何函数
			float G = GGX_Geometry(roughness, view, MicroNormal, normal)
				* GGX_Geometry(roughness, lightDir, MicroNormal, normal);

			//采样环境光CubeMap
			vec3 SampleColor = texture(skyboxCubeMap, lightDir).rgb;
			
			// Incident light = SampleColor * NoL
			// Microfacet specular = D*G*F / (4*NoL*NoV)
			// pdf = D * NoH / (4 * VoH)
			radiance += SampleColor * F * G * VoH / (NoH * NoV);
		}
	}

	//平均高光与高光系数：
	kS /= sampleCount;
	radiance /= sampleCount;
	
	return radiance;
}

void main()
{
	//绝缘体的固定F0
	vec3 F0dielectrics = vec3(0.1, 0.1, 0.1);
	
	//uv：
	vec2 uv = vs_fs_TexCoord;
	
	//Albedo：从贴图采样
	vec3 Albedo = texture(albedoTexture, uv).rgb;
	//金属性：从贴图采样
	float Metallic = texture(metallicTexture, uv).r;
	//粗糙度：从贴图采样
	float Roughness = texture(roughnessTexture, uv).r;
	//最终的F0：根据金属性来插值
	vec3 F0 = mix(F0dielectrics, Albedo, Metallic);
	//基础色：当前等于Albedo
	vec3 BaseColor = Albedo;

	//--------------------------------------------------------
	//计算法线方向：
	vec3 NormalDir = normalize(vs_fs_normal);
	{
		//切线空间的法线
		vec4 TangentNormal =  texture(normalTexture, uv);
		TangentNormal = TangentNormal * 2 - vec4(1, 1, 1, 1);
	
		//切线空间三轴在模型空间的基向量：
		vec3 BaseN = normalize(vs_fs_normal);
		vec3 BaseT = normalize(vs_fs_tangent);
		vec3 BaseB = cross(BaseT,BaseN);
		
		//模型空间的法线方向：
		NormalDir = BaseT*TangentNormal.x + BaseB*TangentNormal.y + BaseN*TangentNormal.z;
	}
	//--------------------------------------------------------

	//视线方向
	vec3 V = normalize(ub_SceneData.eyePosition.xyz - vs_fs_worldPosition);

	//高光系数（会被之后计算）
	vec3 kS = vec3(0,0,0);
	//高光颜色由
	vec3 SpecularColor = CookTorranceSpecular(NormalDir, V, Roughness, F0, kS);

	//漫反射系数：
	vec3 kD = (vec3(1,1,1) - kS);
	//漫反射颜色：
	vec3 DiffuseColor = texture(skyboxDiffuseCubeMap, NormalDir).rgb * BaseColor;
	
	//输出最终颜色！
	fColor = vec4(DiffuseColor * kD + SpecularColor, 1);
}
